package com.cicoding.uhfreader;

import com.cicoding.config.WebSocket;
import com.cicoding.config.ZebraUHFProperties;
import com.cicoding.domian.KufangData;
import com.cicoding.utlis.JdbcUtils;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.uhf.alm.CabinetAlgorithm;
import com.uhf.alm.Rfmodels;
import com.uhf.alm.TagModel;
import com.uhf.api.cls.GpiInfo_ST;
import com.uhf.api.cls.ReadListener;
import com.uhf.api.cls.Reader;
import com.uhf.listener.ReadExceptionListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

@Slf4j
@Component
public class CabinetModeReadData {



    @Resource
    private ZebraUHFProperties zebraUHFProperties;

    private ScheduledExecutorService scheduledExecutorService;
    /**
     * 读写次数
     */
    private Map<String, Integer> redNumMap = new HashMap<>();

    //初始化数据 和上次数据,常量用于做对比

    //初始化数据,之后的数据用来对比
    private Cache<String, Long> cache  = CacheBuilder.newBuilder()
            .maximumSize(5000) // 可以根据需求设置缓存大小限制，比如1000条记录
            .build();

    Cache<String, Long>  RFIDCache = CacheBuilder.newBuilder()
            .expireAfterWrite(1000, TimeUnit.MINUTES)
            .build();

    /**
     * 读写器是否初始化
     */
    private Map<String, Reader> readerMap = new ConcurrentHashMap<>();

    private ConcurrentHashMap<String, Reader> ipStatus = new ConcurrentHashMap<>();

    //记录状态
    private ConcurrentHashMap<Integer, Integer> ipJL = new ConcurrentHashMap<>();

    private ConcurrentHashMap<String, CabinetAlgorithm> CAList = new ConcurrentHashMap<>();


    Cache<String, String>  sqlData = CacheBuilder.newBuilder()
            .build();



    private ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();



    Reader Jreader;

    CabinetAlgorithm CA;

    @Value("${uhfReadMode.antennaDwellTime}")
    private Integer antennaDwellTime;

    @Value("${uhfReadMode.maximumPower}")
    private Integer maximumPower;

    private boolean flage;

    @Resource
    private WebSocket webSocket;

    public boolean openReader() {
        boolean isInit = false;
        scheduledExecutorService = Executors.newScheduledThreadPool(zebraUHFProperties.getConfigs().size());
        for (ZebraUHFProperties.ZebraUHF zebraUHF : zebraUHFProperties.getConfigs()) {
            isInit = initReader(zebraUHF) ? true : isInit;
        }



        return isInit;
    }


    public  void query() throws Exception {
        Connection conn = JdbcUtils.getConnect();
        Statement stat = conn.createStatement();
        ResultSet rs = stat.executeQuery("select * from kufangxinxis");
        List<KufangData> list = new ArrayList<>();
        while (rs.next()) {
            sqlData.put(rs.getString("code"),rs.getString("name"));
        }
        JdbcUtils.close(conn, rs);
        // return list;
    }


    public void checkGpi() {
        GpiInfo_ST gpist=new GpiInfo_ST();
        Reader.READER_ERR readerErr1 = Jreader.GetGPIEx(gpist);
        if (readerErr1 == Reader.READER_ERR.MT_OK_ERR){
            for(int i=0;i<gpist.gpiCount;i++){
                System.out.println("get gpi>>>>" + (gpist.gpiStats[i].GpiId) + ":"
                        + gpist.gpiStats[i].State);
                if (gpist.gpiStats[i].State == 0){
                    System.out.println("get gpi>>>>" + (gpist.gpiStats[i].GpiId) + ":"
                            + gpist.gpiStats[i].State);
                    if (flage){
                        startReadTags();
                    }
                } else if (gpist.gpiStats[i].State == 1) {

                }
            }

        }
    }


    public void checkGpis() {
        for (Map.Entry<String, Reader> entry : readerMap.entrySet()) {
            String ip = entry.getKey();
            Reader reader = entry.getValue();
            GpiInfo_ST gpist = new GpiInfo_ST();
            Reader.READER_ERR readerErr1 = reader.GetGPIEx(gpist);
            if (readerErr1 == Reader.READER_ERR.MT_OK_ERR) {
                for (int i = 0; i < gpist.gpiCount; i++) {

                   /* System.out.println("get gpi>>>>" + (gpist.gpiStats[i].GpiId) + ":"
                            + gpist.gpiStats[i].State +" --- ip -- " +ip
                            +" - Reader.READER_ERR.MT_OK_ERR --- " +Reader.READER_ERR.MT_OK_ERR);*/
                    String stats = gpist.gpiStats[i].State+"";

                    // System.out.println("--- stats -- "+ stats);
                    if (stats.equals("0")) {
                        //  System.out.println("--- tttt -- "+ ipStatus.get(ip));
                        if (null == ipStatus.get(ip)){
                            //   System.out.println("--- 55555 -- "+ stats);
                            ipStatus.put(ip,reader);
                            scheduleTaskWithDelayAndClose(10);
                        }
                        System.out.println("get gpi>>>>" + (gpist.gpiStats[i].GpiId) + ":"
                                + gpist.gpiStats[i].State +"ip -- " +ip
                                +" - Reader.READER_ERR.MT_OK_ERR --- " +Reader.READER_ERR.MT_OK_ERR);
                    } else if (gpist.gpiStats[i].State == 1) {

                    }
                }

            } else {
                log.error("读写器[{}]获取GPI状态出错: {}", ip, readerErr1);
            }
        }
    }



    public void checkGpis1() {
        for (Map.Entry<String, Reader> entry : readerMap.entrySet()) {
            String ip = entry.getKey();
            Reader reader = entry.getValue();
            GpiInfo_ST gpist = new GpiInfo_ST();
            Reader.READER_ERR readerErr1 = reader.GetGPIEx(gpist);

            if (readerErr1 == Reader.READER_ERR.MT_OK_ERR) {
                for (int i = 0; i < gpist.gpiCount; i++) {
                   /* System.out.println("get gpi>>>>" + (gpist.gpiStats[i].GpiId) + ":"
                            + gpist.gpiStats[i].State +" --- ip -- " +ip
                            +" - Reader.READER_ERR.MT_OK_ERR --- " +Reader.READER_ERR.MT_OK_ERR);*/
                    String stats = gpist.gpiStats[i].State+"";
                    if (stats.equals("0")) {
                        ipJL.put(gpist.gpiStats[i].GpiId,gpist.gpiStats[i].State);
                    }else if (null != ipJL.get(gpist.gpiStats[i].GpiId)){
                        System.out.println("检测到了-开始执行");
                        if (null == ipStatus.get(ip)){
                            executor.execute(() -> scheduleTaskWithDelayAndClose(10));
                        }
                        ipJL.remove(gpist.gpiStats[i].GpiId);
                    }
                }

            } else {
                log.error("读写器[{}]获取GPI状态出错: {}", ip, readerErr1);
            }
        }
    }





    private boolean initReader(ZebraUHFProperties.ZebraUHF zebraUHF) {
           // 创建读写器，传入读写器地址串口或者网口，天线口总个数
           // READER_ERR
           String ip = zebraUHF.getIP();
            Jreader = readerMap.get(ip);
           if (Jreader != null) {
               readerMap.remove(ip);
             //  startMap.remove(ip);
               Jreader.CloseReader();
           }
           Jreader = new Reader();
           // 创建读写器，传入读写器地址串口或者网口，天线口总个数
           Reader.READER_ERR er = Jreader.InitReader_Notype(zebraUHF.getIP(), zebraUHF.getPortNum());
           System.out.println(er.toString());
           if (er != Reader.READER_ERR.MT_OK_ERR)
               return false;
           Reader.HardwareDetails val = Jreader.new HardwareDetails();
           er = Jreader.GetHardwareDetails(val);
           //获取版本信息
           Reader.ReaderVersion rdrver = Jreader.new ReaderVersion();
           Jreader.ParamGet(Reader.Mtr_Param.MTR_PARAM_READER_VERSION, rdrver);

           System.out.println("module:" + val.module.toString() + "\r\nsoftwareVer:" +
                   rdrver.softwareVer + "\r\nhardwareVer:" + rdrver.hardwareVer);
           //获取可配置的最大功率，最小功率
           int[] maxpower = new int[1];
           maxpower[0] = 0;
           Jreader.ParamGet(Reader.Mtr_Param.MTR_PARAM_RF_MAXPOWER, maxpower);
           System.out.println("max:" + maxpower[0]);
           int[] minpower = new int[1];
           minpower[0] = 0;
           Jreader.ParamGet(Reader.Mtr_Param.MTR_PARAM_RF_MINPOWER, minpower);
           System.out.println("min:" + minpower[0]);

           Reader.AntPowerConf apcf2 = Jreader.new AntPowerConf();
           er = Jreader.ParamGet(Reader.Mtr_Param.MTR_PARAM_RF_ANTPOWER, apcf2);
           for (int i = 0; i < apcf2.antcnt; i++) {
               System.out.print("antid:" + apcf2.Powers[i].antid);
               System.out.print(" rp:" + apcf2.Powers[i].readPower);
               System.out.print(" wp:" + apcf2.Powers[i].writePower);
               System.out.println();
           }

           //设置北美频段   可以根据实际修改
           Reader.Region_Conf rcf1 = Reader.Region_Conf.RG_NA;
           er = Jreader.ParamSet(Reader.Mtr_Param.MTR_PARAM_FREQUENCY_REGION, rcf1);

           //设置是否检测天线，如果需要使用不可检测的天线（即无法检测天线是否连接在天线端口上）需要此项设置。
           er = Jreader.ParamSet(Reader.Mtr_Param.MTR_PARAM_READER_IS_CHK_ANT, new int[]{0});
           readerMap.put(ip, Jreader);
           return true;
       }
    public boolean startReadTags() {
        log.info("打开读写器");
        AtomicBoolean isStart = new AtomicBoolean(false);
        //stopMap.clear();
        for (ZebraUHFProperties.ZebraUHF zebraUHF : zebraUHFProperties.getConfigs()) {
            isStart.set(startReaders(zebraUHF) || isStart.get());
        }
        return true;
    }


    public void compareCachesAndPrintMessages() {
        Map<String, Long> cacheData = cache.asMap();
        //Map<String, Long> cacheData = NestedCacheExample.getFromNestedCacheData(IP).asMap();
        Map<String, Long> RFIDCacheData = RFIDCache.asMap();
        //Map<String, Long> RFIDCacheData = RFIDCacheExample.getFromNestedCacheData(IP).asMap();

        Iterator<Map.Entry<String, Long>> cacheIterator = cacheData.entrySet().iterator();
        while (cacheIterator.hasNext()) {
            Map.Entry<String, Long> entry = cacheIterator.next();
            String key = entry.getKey();
            if (!RFIDCacheData.containsKey(key)) {
                if (sqlData.asMap().containsKey(key)) {
                    String value = sqlData.getIfPresent(key);
                    System.out.println(key + " -  (出库) 工器具"+value);
                    webSocket.sendInfo(key + " -  (出库) 工器具"+value,"89");
                    cacheIterator.remove(); // Remove the data from cacheData
                }
            }
        }

        Iterator<Map.Entry<String, Long>> RFIDIterator = RFIDCacheData.entrySet().iterator();
        List<String> keysToAdd = new ArrayList<>();
        while (RFIDIterator.hasNext()) {
            Map.Entry<String, Long> entry = RFIDIterator.next();
            String key = entry.getKey();
            if (!cacheData.containsKey(key)) {
                if (sqlData.asMap().containsKey(key)) {
                    keysToAdd.add(key);
                    String value = sqlData.getIfPresent(key);
                    webSocket.sendInfo(key + " -  (入库) 工器具"+value,"89");
                    System.out.println(key + " -  (入库) 工器具"+value);
                }
            }
        }
        // System.out.println();

        String cache = "";

        for (Map.Entry<String, Long> entry : cacheData.entrySet()) {
            cache += entry.getKey() +" , ";
            // System.out.println("Tag: " + entry.getKey() + ", Value: " + entry.getValue());
        }
        String rfid = "";

        for (Map.Entry<String, Long> entry : RFIDCacheData.entrySet()) {
            rfid += entry.getKey() + " , ";
            //System.out.println("Tag: " + entry.getKey() + ", Value: " + entry.getValue());
        }

        System.out.println("\nRFID Cache Data: "+ cache);
        System.out.println("\nRFID rfid Data: "+ rfid);
        // Add the new keys to cacheData
        for (String key : keysToAdd) {
            cacheData.put(key, System.currentTimeMillis());
        }
        try {
            //    webSocket.sendInfo("3333","89");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        RFIDCache.invalidateAll();
    }




    //开启读写器
    public synchronized boolean startReaders(ZebraUHFProperties.ZebraUHF zebraUHF) {
        // log.error("开始执行-----{} ", zebraUHF);
        String ip = zebraUHF.getIP();
        Reader Jreader = readerMap.get(ip);
        ipStatus.put(ip,Jreader);
        TagModel tm = new TagModel();
        tm.setGen2Target(2);// A 0，B 1，A-B 2，B-A 3
        tm.setS2_AInstruct(true);//S2->A  true 启用，false 不启用
        List<Rfmodels> lrflist = new ArrayList<Rfmodels>();
        Rfmodels rf1 = new Rfmodels();
        rf1.setCount(2);// 次数 需>=1
        rf1.setQval(-1);//-1 自动 0-15 为静态Q
        rf1.setTime(antennaDwellTime);//天线驻留时间
        rf1.setRfModel("RF_MODE_7");
        lrflist.add(rf1);
        rf1 = new Rfmodels();
        rf1.setCount(2);// 次数 需>=1
        rf1.setQval(3);//-1 自动 0-15 为静态Q
        rf1.setTime(antennaDwellTime);//天线驻留时间
        rf1.setRfModel("RF_MODE_13");
        lrflist.add(rf1);
        tm.setrflist(lrflist);
        CA = new CabinetAlgorithm(Jreader, maximumPower, tm);
        //  CabinetAlgorithm CA = new CabinetAlgorithm(Jreader, 3300, tm);
        CA.addReadExceptionListener(REL);
        CA.addReadListener(RL);

        //天线数组，数组元素为对应的物理天线号，从1开始。
        int[] ants = Arrays.asList(zebraUHF.getAntArray().split(",")).stream().mapToInt(Integer::parseInt).toArray();
        for (int i = 0; i < ants.length; i++)
            ants[i] = i + 1;
        //设置控制返回标签属性项
        int option = 0;
       // st = st + 1;
        //开始
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd :hh:mm:ss");
        //开始盘点
        log.error("天线" + ip + "Preparationforwork {}", dateFormat.format(new Date()));
        Reader.READER_ERR re = CA.Preparationforwork(CabinetAlgorithm.IT_MODE.IT_MODE_BOXV1);
        //hashMaps.remove(ip);
       // concurrentHashMap.clear();
        //allTags_V.clear();
        log.error("天线" + ip + "AsyncStartReading_IT {}", dateFormat.format(new Date()));
      //  deredMap.put(ip, true);
        CA.AsyncStartReading_IT(CabinetAlgorithm.IT_MODE.IT_MODE_BOXV1, ants, ants.length, option);

        CAList.put(ip, CA);
        return true;
    }






    /**
     * 标签监听
     */
    ReadListener RL = new ReadListener() {
        @Override
        public void tagRead(Reader r, final Reader.TAGINFO[] tag) {
            // TODO Auto-generated method stub
            Vector<String> code1 = new Vector<String>();
            for (Reader.TAGINFO taginfo : tag) {
                String code = Reader.bytes_Hexstr(taginfo.EpcId);
                // checkGpi();
                SimpleDateFormat dateFormat1 = new SimpleDateFormat("yyyy-MM-dd :hh:mm:ss");
                //concurrentHashMap.put(code, dateFormat1.format(new Date()));
                // hashMaps.put(r.GetReaderAddress(), concurrentHashMap);
                long timeMillis = System.currentTimeMillis();
                if(flage){
                    cache.put(code, timeMillis);
                    log.error("--首轮打印标签---- {} ip是多少 {} ",code,r.GetReaderAddress());
                }else{
                    RFIDCache.put(code,timeMillis);
                }



                //  code1.add(code);
                //concurrentHashMap.put(r.GetReaderAddress(),code1);
                // handleTags.handleTag(code);
            }
        }
    };

    ReadExceptionListener REL = new ReadExceptionListener() {

        @Override
        public void tagReadException(Reader r, Reader.READER_ERR re, String errmsg) {
            String address = r.GetReaderAddress();

            log.error("[zebraUHF]读写器[{}]异常信息: {} ", address, re);
            //判断是否异常发生过于频繁

            if (Reader.READER_ERR.MT_CMD_FAILED_ERR == re || Reader.READER_ERR.MT_CMD_NO_TAG_ERR == re) {
                return;
            }

            ZebraUHFProperties.ZebraUHF readerZebraUHF = null;
            for (ZebraUHFProperties.ZebraUHF zebraUHF : zebraUHFProperties.getConfigs()) {
                if (address.equals(zebraUHF.getIP())) {
                    readerZebraUHF = zebraUHF;
                }
            }
            if (readerZebraUHF == null) {
                return;
            }
            //尝试重新连接读写器并启动盘存操作
            boolean reConnect = false;
            r.AsyncStopReading_IT();
        }
    };




    public boolean stopReadTags() {
        log.error("停止盘存");
        for (String ip : CAList.keySet()) {
            CabinetAlgorithm rdr = CAList.get(ip);

            ipStatus.remove(ip);
            // startMap.remove(ip);
            // stopMap.put(ip, true);
           /* if (schedule != null) {
                //  log.error("停止盘存", ip);
                schedule.cancel(true);
            }*/
            //停止
            rdr.AsyncStopReading_IT();
        }
        //startMap.clear();
        return true;
    }


    public void scheduleTaskWithDelayAndClose(int delayInSeconds) {
        flage = false;
        executor.schedule(() -> {
            try {
                // 在延迟之前执行关闭方法
                // System.out.println("执行关闭其他方法...");
                for (ZebraUHFProperties.ZebraUHF zebraUHF : zebraUHFProperties.getConfigs()) {
                    startReaders(zebraUHF);
                    Thread.sleep(100); // 每秒钟检查一次
                }

                // 延迟指定秒数后执行任务
                executor.schedule(() -> {
                    // 执行需要延迟执行的任务
                    compareCachesAndPrintMessages();
                    //  System.out.println("执行延迟任务...");
                    stopReadTags();
                }, delayInSeconds, TimeUnit.SECONDS);
            } catch (Exception e) {
                // 处理异常
                e.printStackTrace();
            }
        }, 0, TimeUnit.SECONDS);
    }

    public void scheduleTaskWithDelay(int delayInSeconds) {
        flage = true;
        executor.schedule(() -> {
            try {
                // 在延迟之前执行关闭方法
                // System.out.println("执行关闭其他方法...");
                startReadTags();
                executor.schedule(() -> {
                    // 执行需要延迟执行的任务
                    stopReadTags();
                }, delayInSeconds, TimeUnit.SECONDS);
            } catch (Exception e) {
                // 处理异常
                e.printStackTrace();
            }
        }, 0, TimeUnit.SECONDS);
    }

}
